home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / arpd / arpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-17  |  14.6 KB  |  568 lines

  1. /* 
  2.  * arpd.c --
  3.  *
  4.  *    A program to reply to ARP and RARP requests.  This program
  5.  *    only translates between Internet and Ethernet addresses.  See
  6.  *    RFC826 for details of the ARP protocol, and RFC903 for details
  7.  *    of the RARP protocol.
  8.  *
  9.  * Copyright 1989 Regents of the University of California
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /sprite/src/daemons/arpd/RCS/arpd.c,v 1.5 92/06/16 21:17:19 jhh Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <errno.h>
  28. #include <host.h>
  29. #include <option.h>
  30. #include <sys/socket.h>
  31. #include <net/if_arp.h>
  32. #include <netinet/if_ether.h>
  33. #include <netinet/in.h>
  34. #include <sys/file.h>
  35. #include <sys/param.h>
  36. #include <sys/stat.h>
  37. #include <sys/time.h>
  38. #include <sys/types.h>
  39.  
  40. /*
  41.  * Command line options.
  42.  */
  43.  
  44. static int verbose = 0;
  45. static char *hostFile = NULL;
  46.  
  47. static Option optionArray[] = {
  48.     {OPT_TRUE,   "v", (char *) &verbose, "Turn on informational output"},
  49.     {OPT_STRING, "f", (char *) &hostFile, "Name of host database file"},
  50. };
  51. static int numOptions = sizeof(optionArray) / sizeof(Option);
  52.  
  53. /*
  54.  * One structure of the following type is created for each entry
  55.  * in the host table.  This saves us from having to regenerate the
  56.  * host table except when it changes.
  57.  */
  58.  
  59. typedef struct HostInfo {
  60.     char *name;            /* Textual name for this host. */
  61.     Net_InetAddress inetAddr;    /* Internet address for this host. */
  62.     Net_EtherAddress etherAddr;    /* Ethernet address for this host. */
  63.     struct HostInfo *nextPtr;    /* Next in list of all known hosts (NULL
  64.                  * for end of list). */
  65. } HostInfo;
  66.  
  67. HostInfo *hostList = NULL;    /* First in list of all known hosts. */
  68. int modTime = -1;        /* The information in memory corresponds to
  69.                  * this modify time on the host file. */
  70.  
  71. /*
  72.  * The ARP/RARP packet size is defined below.  Because of structure
  73.  * alignment differences between machines, it isn't safe to use
  74.  * sizeof with the structure.
  75.  */
  76.  
  77. #define ARP_PACKET_SIZE 42
  78.  
  79. /*
  80.  * The variable below holds the name of the host on which this program
  81.  * is running, and a pointer to the corresponding entry from the hosts
  82.  * file (NULL means no corresponding entry could be found in the hosts
  83.  * file).
  84.  */
  85.  
  86. char myName[MAXHOSTNAMELEN+1];
  87. HostInfo *myInfoPtr = NULL;
  88.  
  89. static void        DoArp();
  90. static void        DoRarp();
  91. static void        UpdateTable();
  92.  
  93. /*
  94.  *----------------------------------------------------------------------
  95.  *
  96.  * main --
  97.  *
  98.  *    The main loop of the ARP request handler. Packets are 
  99.  *    read from the netwok and examined to see if we can make a 
  100.  *    reply.
  101.  *
  102.  * Results:
  103.  *    None.
  104.  *
  105.  * Side effects:
  106.  *    None.
  107.  *
  108.  *----------------------------------------------------------------------
  109.  */
  110.  
  111. main(argc, argv)
  112.     int        argc;
  113.     char    **argv;
  114. {
  115.     int            arpID, rarpID;
  116.  
  117.     if (Opt_Parse(argc, argv,  optionArray, numOptions, 0) > 1) {
  118.     printf("arpd ignoring extra arguments\n");
  119.     }
  120.  
  121.     if (hostFile != NULL) {
  122.     if (Host_SetFile(hostFile)) {
  123.         perror("arpd couldn't set host file to \"%s\"", hostFile);
  124.         exit(1);
  125.     }
  126.     }
  127.  
  128.     /*
  129.      * Open the network devices, and read in the host database.  If
  130.      * either of these fails, then just quit right now.
  131.      */
  132.  
  133.     arpID = open("/dev/etherARP", O_RDWR, 0600); 
  134.     if (arpID < 0) {
  135.     perror("arpd couldn't open /dev/etherARP");
  136.     exit(1);
  137.     }
  138.     rarpID = open("/dev/etherRARP", O_RDWR, 0600); 
  139.     if (rarpID < 0) {
  140.     perror("arpd couldn't open /dev/etherRARP");
  141.     exit(1);
  142.     }
  143.     if (gethostname(myName, MAXHOSTNAMELEN+1) < 0) {
  144.     perror("arpd couldn't get host name from gethostname()");
  145.     exit(1);
  146.     }
  147.     UpdateTable();
  148.     if (modTime == -1) {
  149.     exit(1);
  150.     }
  151.  
  152.     /*
  153.      * Enter an infinite loop servicing ARP and RARP requests.
  154.      */
  155.  
  156.     while (1) {
  157.     int readMask, numReady;
  158.  
  159.     readMask = (1 << arpID) | (1 << rarpID);
  160.     numReady = select(rarpID+1, &readMask, (int *) NULL,
  161.         (int *) NULL, (struct timeval *) NULL);
  162.     if ((numReady < 0) && (errno != EINTR)) {
  163.         printf("arpd couldn't select on network devices: %s\n",
  164.             strerror(errno));
  165.         exit(1);
  166.     }
  167.  
  168.     if (readMask & (1 << arpID)) {
  169.         DoArp(arpID);
  170.     }
  171.     if (readMask & (1 << rarpID)) {
  172.         DoRarp(rarpID);
  173.     }
  174.     }
  175. }
  176.  
  177. /*
  178.  *----------------------------------------------------------------------
  179.  *
  180.  * DoArp --
  181.  *
  182.  *    Handle an ARP request.
  183.  *
  184.  * Results:
  185.  *    None.
  186.  *
  187.  * Side effects:
  188.  *    A response is transmitted for the ARP request.
  189.  *
  190.  *----------------------------------------------------------------------
  191.  */
  192.  
  193. static void
  194. DoArp(streamID)
  195.     int streamID;        /* Integer stream # for ARP device. */
  196. {
  197.     struct {
  198.     struct ether_header hdr;
  199.     struct ether_arp arp;
  200.     } packet;
  201.     int bytesRead, bytesWritten, etherType, protocolType, hardwareType, arpOp;
  202.     unsigned long senderAddr, targetAddr;
  203.     register HostInfo *infoPtr;
  204.  
  205.     /*
  206.      * Read and validate the ARP packet.
  207.      */
  208.  
  209.     bytesRead = read(streamID, (char *) &packet, ARP_PACKET_SIZE);
  210.     if (bytesRead < 0) {
  211.     printf("arpd couldn't read ARP packet: %s\n",
  212.         strerror(errno));
  213.     return;
  214.     }
  215.     if (bytesRead < ARP_PACKET_SIZE) {
  216.     printf("arpd got short ARP packet: only %d bytes\n",
  217.         bytesRead);
  218.     return;
  219.     }
  220.     etherType = ntohs(packet.hdr.ether_type);
  221.     if (etherType != ETHERTYPE_ARP) {
  222.     printf("arpd got ARP packet with ether_type 0x%x\n",
  223.         etherType);
  224.     return;
  225.     }
  226.     arpOp = ntohs(packet.arp.ea_hdr.ar_op);
  227.     if (arpOp != ARPOP_REQUEST) {
  228.     if (verbose) {
  229.         printf("arpd got ARP packet with unknown op %d\n",
  230.             arpOp);
  231.     }
  232.     return;
  233.     }
  234.     hardwareType = ntohs(packet.arp.ea_hdr.ar_hrd);
  235.     if (hardwareType != ARPHRD_ETHER) {
  236.     if (verbose) {
  237.         printf("arpd got ARP packet with unknown hardware type 0x%x\n",
  238.             hardwareType);
  239.     }
  240.     return;
  241.     }
  242.     protocolType = ntohs(packet.arp.ea_hdr.ar_pro);
  243.     if (protocolType != ETHERTYPE_IP) {
  244.     if (verbose) {
  245.         printf("arpd got ARP packet with unknown protocol type 0x%x\n",
  246.             protocolType);
  247.     }
  248.     return;
  249.     }
  250.     UpdateTable();
  251.  
  252.     /*
  253.      * Look for an entry in our host database that matches the given
  254.      * protocol address.  The bcopy calls below are needed because
  255.      * integers may not be properly aligned in the packet.
  256.      */
  257.  
  258.     bcopy((char *) packet.arp.arp_spa, (char *) &senderAddr,
  259.         sizeof(senderAddr));
  260.     bcopy((char *) packet.arp.arp_tpa, (char *) &targetAddr,
  261.         sizeof(targetAddr));
  262.     if (verbose) {
  263.     struct timeval time;
  264.     char *string;
  265.     char buffer1[32];
  266.     char buffer2[32];
  267.  
  268.     gettimeofday(&time, (struct timezone *) NULL);
  269.     string = ctime(&time.tv_sec);
  270.     string[24] = 0;
  271.     printf("ARP at %s from %s for %s", string, 
  272.         Net_InetAddrToString(senderAddr, buffer1), 
  273.         Net_InetAddrToString(targetAddr, buffer2));
  274.     }
  275.     for (infoPtr = hostList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
  276.     if (infoPtr->inetAddr == targetAddr) {
  277.         break;
  278.     }
  279.     }
  280.     if (infoPtr == NULL) {
  281.     if (verbose) {
  282.         printf(": unknown target\n");
  283.     }
  284.     return;
  285.     }
  286.     if (verbose) {
  287.     char    buffer[20];
  288.     printf(": %s\n", Net_EtherAddrToString(&infoPtr->etherAddr, buffer));
  289.     }
  290.  
  291.     /*
  292.      * Reverse sender and target fields, and respond with the appropriate
  293.      * Ethernet address.  No need to fill in the source in the packet
  294.      * header:  the kernel automatically overwrites it.
  295.      */
  296.  
  297.     bcopy((char *) &targetAddr, (char *) packet.arp.arp_spa,
  298.         sizeof(targetAddr));
  299.     bcopy((char *) &senderAddr, (char *) packet.arp.arp_tpa,
  300.         sizeof(senderAddr));
  301.     bcopy((char *) packet.arp.arp_sha, (char *) packet.arp.arp_tha,
  302.         sizeof(Net_EtherAddress));
  303.     bcopy((char *) &infoPtr->etherAddr, (char *) packet.arp.arp_sha,
  304.         sizeof(Net_EtherAddress));
  305.     packet.arp.ea_hdr.ar_op = htons(ARPOP_REPLY);
  306.     bcopy((char *) packet.hdr.ether_shost, (char *) packet.hdr.ether_dhost,
  307.         sizeof(Net_EtherAddress));
  308.     bytesWritten = write(streamID, (char *) &packet, ARP_PACKET_SIZE);
  309.     if (bytesWritten < 0) {
  310.     printf("arpd couldn't send ARP response: %s\n",
  311.         strerror(errno));
  312.     return;
  313.     }
  314.     if (bytesWritten != ARP_PACKET_SIZE) {
  315.     printf("arpd short write of ARP response: %d bytes\n",
  316.         bytesWritten);
  317.     return;
  318.     }
  319. }
  320.  
  321. /*
  322.  *----------------------------------------------------------------------
  323.  *
  324.  * DoRarp --
  325.  *
  326.  *    Handle a RARP request.
  327.  *
  328.  * Results:
  329.  *    None.
  330.  *
  331.  * Side effects:
  332.  *    A response is transmitted for the RARP request.
  333.  *
  334.  *----------------------------------------------------------------------
  335.  */
  336.  
  337. static void
  338. DoRarp(streamID)
  339.     int streamID;        /* Integer stream # for ARP device. */
  340. {
  341.     struct {
  342.     struct ether_header hdr;
  343.     struct ether_arp arp;
  344.     } packet;
  345.     int bytesRead, bytesWritten, etherType, protocolType, hardwareType, arpOp;
  346.     unsigned long senderAddr, targetAddr;
  347.     register HostInfo *infoPtr;
  348.  
  349.     /*
  350.      * Read and validate the ARP packet.
  351.      */
  352.  
  353.     bytesRead = read(streamID, (char *) &packet, ARP_PACKET_SIZE);
  354.     if (bytesRead < 0) {
  355.     printf("arpd couldn't read RARP packet: %s\n",
  356.         strerror(errno));
  357.     return;
  358.     }
  359.     if (bytesRead < ARP_PACKET_SIZE) {
  360.     printf("arpd got short RARP packet: only %d bytes\n",
  361.         bytesRead);
  362.     return;
  363.     }
  364.     etherType = ntohs(packet.hdr.ether_type);
  365.     if (etherType != ETHERTYPE_RARP) {
  366.     printf("arpd got ARP packet with ether_type 0x%x\n",
  367.         etherType);
  368.     return;
  369.     }
  370.     arpOp = ntohs(packet.arp.ea_hdr.ar_op);
  371.     if (arpOp != REVARP_REQUEST) {
  372.     if (verbose) {
  373.         printf("arpd got RARP packet with unknown op %d\n", arpOp);
  374.     }
  375.     return;
  376.     }
  377.     hardwareType = ntohs(packet.arp.ea_hdr.ar_hrd);
  378.     if (hardwareType != ARPHRD_ETHER) {
  379.     if (verbose) {
  380.         printf("arpd got RARP packet with unknown hardware type 0x%x\n",
  381.             hardwareType);
  382.     }
  383.     return;
  384.     }
  385.     protocolType = ntohs(packet.arp.ea_hdr.ar_pro);
  386.     if (protocolType != ETHERTYPE_IP) {
  387.     if (verbose) {
  388.         printf("arpd got RARP packet with unknown protocol type 0x%x\n",
  389.             protocolType);
  390.     }
  391.     return;
  392.     }
  393.     UpdateTable();
  394.  
  395.     /*
  396.      * Look for an entry in our host database that matches the given
  397.      * protocol address.  The bcopy calls below are needed because
  398.      * integers may not be properly aligned in the packet.
  399.      */
  400.  
  401.     if (verbose) {
  402.     struct timeval time;
  403.     char *string;
  404.     char ether1[20];
  405.     char ether2[20];
  406.  
  407.     gettimeofday(&time, (struct timezone *) NULL);
  408.     string = ctime(&time.tv_sec);
  409.     string[24] = 0;
  410.     printf("RARP at %s from %s for %s", string, 
  411.         Net_EtherAddrToString((Net_EtherAddress *) packet.arp.arp_sha,
  412.             ether1),
  413.         Net_EtherAddrToString((Net_EtherAddress *) packet.arp.arp_tha,
  414.             ether2));
  415.     }
  416.     for (infoPtr = hostList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
  417.     if (Net_EtherAddrCmpPtr((Net_EtherAddress *) packet.arp.arp_sha, 
  418.         &infoPtr->etherAddr) == 0) {
  419.         break;
  420.     }
  421.     }
  422.     if (infoPtr == NULL) {
  423.     if (verbose) {
  424.         printf(": unknown target\n");
  425.     }
  426.     return;
  427.     }
  428.     targetAddr = infoPtr->inetAddr;
  429.     if (verbose) {
  430.     char    inet[32];
  431.     printf(": %s\n", Net_InetAddrToString((Net_InetAddress) targetAddr,
  432.             inet));
  433.     }
  434.  
  435.     /*
  436.      * Reverse sender and target fields, and respond with the appropriate
  437.      * Internet address.  No need to fill in the source in the packet
  438.      * header:  the kernel automatically overwrites it.
  439.      */
  440.  
  441.     bcopy((char *) packet.arp.arp_sha, (char *) packet.arp.arp_tha,
  442.         sizeof(Net_EtherAddress));
  443.     bcopy((char *) &targetAddr, (char *) packet.arp.arp_tpa,
  444.         sizeof(targetAddr));
  445.     if (myInfoPtr != NULL) {
  446.     bcopy((char *) &myInfoPtr->etherAddr, (char *) packet.arp.arp_sha,
  447.         sizeof(Net_EtherAddress));
  448.     senderAddr = myInfoPtr->inetAddr;
  449.     bcopy((char *) &senderAddr, (char *) packet.arp.arp_spa,
  450.         sizeof(senderAddr));
  451.     } else {
  452.     bzero((char *) packet.arp.arp_sha, sizeof(Net_EtherAddress));
  453.     bzero((char *) packet.arp.arp_spa, sizeof(senderAddr));
  454.     }
  455.     packet.arp.ea_hdr.ar_op = htons(REVARP_REPLY);
  456.     bcopy((char *) packet.hdr.ether_shost, (char *) packet.hdr.ether_dhost,
  457.         sizeof(Net_EtherAddress));
  458.     bytesWritten = write(streamID, (char *) &packet, ARP_PACKET_SIZE);
  459.     if (bytesWritten < 0) {
  460.     printf("arpd couldn't send RARP response: %s\n",
  461.         strerror(errno));
  462.     return;
  463.     }
  464.     if (bytesWritten != ARP_PACKET_SIZE) {
  465.     printf("arpd short write of RARP response: %d bytes\n",
  466.         bytesWritten);
  467.     return;
  468.     }
  469. }
  470.  
  471. /*
  472.  *----------------------------------------------------------------------
  473.  *
  474.  * UpdateTable --
  475.  *
  476.  *    Make sure that the host information in memory is up-to-date.
  477.  *    If not, throw away what we've got and read in fresh stuff.
  478.  *
  479.  * Results:
  480.  *    None.
  481.  *
  482.  * Side effects:
  483.  *    The information in the list pointed to by hostList is
  484.  *    potentially modified, as is the modTime variable.  The pointer
  485.  *    myInfoPtr is (re-)set to point to the information for the
  486.  *    host named "myName".
  487.  *
  488.  *----------------------------------------------------------------------
  489.  */
  490.  
  491. static void
  492. UpdateTable()
  493. {
  494.     struct stat buf;
  495.     register HostInfo *infoPtr;
  496.     register Host_Entry *hostPtr;
  497.     int            i;
  498.     ReturnStatus    status;
  499.  
  500.     /*
  501.      * See if the current database is up-to-date.  If so,
  502.      * then just return.
  503.      */
  504.  
  505.     if (Host_Stat(&buf) != 0) {
  506.     printf("arpd couldn't stat host file: %s\n", strerror(errno));
  507.     return;
  508.     }
  509.     if (buf.st_mtime == modTime) {
  510.     return;
  511.     }
  512.  
  513.     /*
  514.      * Throw away everything that's currently in memory.
  515.      */
  516.  
  517.     while (hostList != NULL) {
  518.     infoPtr = hostList;
  519.     hostList = infoPtr->nextPtr;
  520.     free(infoPtr->name);
  521.     free((char *) infoPtr);
  522.     }
  523.  
  524.     /*
  525.      * Rebuild the database from the host database file.
  526.      */
  527.  
  528.     if (verbose) {
  529.     char *timeString;
  530.     timeString = ctime(&buf.st_mtime);
  531.     timeString[24] = 0;
  532.     printf("arpd reloading database from host file (modified %s)\n",
  533.         timeString);
  534.     }
  535.  
  536.     if (Host_Start() != 0) {
  537.     printf("arpd: Host_Start failed : %s\n", strerror(errno));
  538.     return;
  539.     }
  540.  
  541.     myInfoPtr = NULL;
  542.     for (hostPtr = Host_Next(); hostPtr != NULL; hostPtr = Host_Next()) {
  543.     for (i = 0; i < hostPtr->numNets; i++) {
  544.         if (hostPtr->nets[i].netAddr.type == NET_ADDRESS_ETHER) {
  545.         infoPtr = (HostInfo *) malloc(sizeof(HostInfo));
  546.         infoPtr->name = malloc((unsigned) (strlen(hostPtr->name) + 1));
  547.         strcpy(infoPtr->name, hostPtr->name);
  548.         infoPtr->inetAddr = hostPtr->nets[i].inetAddr;
  549.         status = Net_GetAddress(&hostPtr->nets[i].netAddr, 
  550.                 &infoPtr->etherAddr);
  551.         if (status != SUCCESS) {
  552.             printf("arpd: Net_GetAddress failed\n");
  553.             goto done;
  554.         }
  555.         infoPtr->nextPtr = hostList;
  556.         hostList = infoPtr;
  557.         if (strcmp(myName, infoPtr->name) == 0) {
  558.             myInfoPtr = infoPtr;
  559.         }
  560.         break;
  561.         }
  562.     }
  563.     }
  564. done:
  565.     Host_End();
  566.     modTime = buf.st_mtime;
  567. }
  568.